package daoOptimize2;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.*;
import java.util.List;

/*
 * DAO：data(base) access object
 * 封装了针对与数据表的通用的操作(考虑事物)
 * 使用DBUtils包提供的对数据库的增删查改的封装操作方法
 * */
public abstract class BaseDAO<T> {

    private QueryRunner queryRunner = new QueryRunner();
    // 定义一个变量来接收泛型的类型
    private Class<T> type;

    // 获取T的Class对象，获取泛型的类型，泛型是在被子类继承时才确定
    public BaseDAO() {
        // 获取子类的类型
        Class clazz = this.getClass();
        // 获取父类的类型
        // getGenericSuperclass()用来获取当前类的父类的类型
        // ParameterizedType表示的是带泛型的类型
        ParameterizedType parameterizedType = (ParameterizedType) clazz.getGenericSuperclass();
        // 获取具体的泛型类型 getActualTypeArguments获取具体的泛型的类型
        // 这个方法会返回一个Type的数组
        Type[] types = parameterizedType.getActualTypeArguments();
        // 获取具体的泛型的类型·
        this.type = (Class<T>) types[0];
    }

    //通用的增删改操作
    public int update(Connection connection, String sql, Object... args) { //sql占位符的个数与可变形参的长度一样
        int count = 0;
        try {
            count = queryRunner.update(connection, sql, args);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return count;
    }


    //通用的查询操作：用于返回数据表中的一条记录
    public T getInstance(Connection connection, String sql, Object... args) {
        T t = null;
        try {
            t = queryRunner.query(connection, sql, new BeanHandler<T>(type), args);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return t;
    }


    //通用的查询操作：返回表中多条记录的集合
    public List<T> getForList(Connection connection, String sql, Object... args) {
        List<T> list = null;
        try {
            list = queryRunner.query(connection, sql, new BeanListHandler<T>(type), args);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return list;
    }


    //用于查询特殊值的通用方法
    public Object getValue(Connection connection, String sql, Object... args) {
        Object count = null;
        try {
            // 调用queryRunner的query方法获取一个单一的值
            count = queryRunner.query(connection, sql, new ScalarHandler(), args);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return count;
    }
}
